﻿using System;
using System.Collections.Generic;
using Assist;
using Autodesk.Revit.DB;
using HYCodeBase.Math;

namespace HYRevitCode.BoundingBoxUtility
{
	public class MinAreaBoundingBoxCalculator
	{
		public static bool MinAreaRect(List<XYZ> vertexes, ref List<XYZ> boxVertexes, ref double length, ref double width)
		{
			MinAreaBoundingBoxCalculator.MinAreaBoundingBox minAreaBoundingBox = default(MinAreaBoundingBoxCalculator.MinAreaBoundingBox);
			if (!MathUtility.GreaterThan(MinAreaBoundingBoxCalculator.MinAreaRect(vertexes, ref minAreaBoundingBox), 0.0))
			{
				return false;
			}
			length = minAreaBoundingBox.hLength * 2.0;
			width = minAreaBoundingBox.hWidth * 2.0;
			boxVertexes = MinAreaBoundingBoxCalculator.GetMinAreaBoundingBoxPoints(minAreaBoundingBox);
			return true;
		}

		private static double MinAreaRect(List<XYZ> vertexes, ref MinAreaBoundingBoxCalculator.MinAreaBoundingBox box)
		{
			double num = MinAreaBoundingBoxCalculator.FLT_MAX;
			double num2 = 0.0;
			double num3 = 0.0;
			int i = 0;
			int index = vertexes.Count - 1;
			while (i < vertexes.Count)
			{
				XYZ xyz = vertexes[i] - vertexes[index];
				xyz = xyz.Normalize();
				XYZ xyz2 = MinAreaBoundingBoxCalculator.RotateTo(xyz, System.Math.PI*.5, XYZ.BasisZ);
				double num4 = 0.0;
				double num5 = 0.0;
				double num6 = 0.0;
				double num7 = 0.0;
				for (int j = 0; j < vertexes.Count; j++)
				{
					XYZ xyz3 = vertexes[j] - vertexes[index];
					double num8 = xyz3.DotProduct(xyz);
					if (MathUtility.LessThan(num8, num4))
					{
						num4 = num8;
					}
					if (MathUtility.GreaterThan(num8, num5))
					{
						num5 = num8;
					}
					num8 = xyz3.DotProduct(xyz2);
					if (MathUtility.LessThan(num8, num6))
					{
						num6 = num8;
					}
					if (MathUtility.GreaterThan(num8, num7))
					{
						num7 = num8;
					}
				}
				double num9 = (num5 - num4) * (num7 - num6);
				if (MathUtility.IsEqual(num9, num, 0.0001))
				{
					double val = Math.Abs(num2 - num3);
					if (MathUtility.LessThan(Math.Abs(num5 - num4 - (num7 - num6)), val))
					{
						num2 = num5 - num4;
						num3 = num7 - num6;
						num = num9;
						box.center = vertexes[index] + (xyz * (num5 + num4) + xyz2 * (num7 + num6)) * 0.5;
						box.xAxis = xyz;
						box.yAxis = xyz2;
						box.hLength = (num5 - num4) * 0.5;
						box.hWidth = (num7 - num6) * 0.5;
					}
				}
				else if (MathUtility.LessThan(num9, num))
				{
					num2 = num5 - num4;
					num3 = num7 - num6;
					num = num9;
					box.center = vertexes[index] + (xyz * (num5 + num4) + xyz2 * (num7 + num6)) * 0.5;
					box.xAxis = xyz;
					box.yAxis = xyz2;
					box.hLength = (num5 - num4) * 0.5;
					box.hWidth = (num7 - num6) * 0.5;
				}
				index = i;
				i++;
			}
			return num;
		}

		private static List<XYZ> GetMinAreaBoundingBoxPoints(MinAreaBoundingBoxCalculator.MinAreaBoundingBox box)
		{
			return new List<XYZ>
			{
				box.center - (box.xAxis * box.hLength + box.yAxis * box.hWidth),
				box.center + (box.xAxis * box.hLength - box.yAxis * box.hWidth),
				box.center + (box.xAxis * box.hLength + box.yAxis * box.hWidth),
				box.center + (box.yAxis * box.hWidth - box.xAxis * box.hLength)
			};
		}

		private static XYZ RotateTo(XYZ pt, double angle, XYZ axis)
		{
			return RevitVersionFuncs.CreateRotationAtPoint(axis, angle, new XYZ(0.0, 0.0, 0.0)).OfPoint(pt);
		}

		private static double FLT_MIN = 1.1754943508222875E-38;

		private static double FLT_MAX = 3.4028234663852886E+38;

		private const double _epsDouble = 1E-09;

		private const double _epsPoint = 0.0001;

		private const double _epsAngle = 0.0001;

		private struct MinAreaBoundingBox
		{
			public MinAreaBoundingBox(XYZ x, XYZ y, XYZ c, double hL, double hW)
			{
				this.xAxis = x;
				this.yAxis = y;
				this.center = c;
				this.hLength = hL;
				this.hWidth = hW;
			}

			public XYZ xAxis;

			public XYZ yAxis;

			public XYZ center;

			public double hLength;

			public double hWidth;
		}
	}
}
